<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>策略模式</title>
    <!-- 
        定义
            策略模式定义了一系列算法分别封装起来，让它们之间可以相互替换，此模式让算法的变化独立于使用算法的的客户。

        优点
            利用组合、委托等技术，可以有效的避免多重条件选择语句
            提供了对开放-封闭原则的完美支持，将算法封装在独立的strategy中，使得它们易于切换扩展
            利用组合和委托来让Context拥有执行算法的能力，这也是继承的一种更轻便的代替方案

        使用
            假如要实现这样一个业务：商城里每个产品都有原价为 originalPrice，但是存在打折促销的情况。规则为：
            部分产品不参与活动： default 状态，原价出售。
            部分产品已预售：pre-sale 状态，原价基础上打八折。
            部分产品参与促销活动：promotion 状态，如果原价不高于100，九折出售；如果原价高于 100，则减20 元。

     -->
</head>

<body>
    <script>
        // 不考虑任何设计模式的写法可能用 if-else 多次判断来计算价格。
        function getPrice(originalPrice, status) {
            if (status === "default") {
                return originalPrice;
            }
            if (status === "pre-sale") {
                return originalPrice * 0.8;
            }
            if (status === "promotion") {
                if (origialPrice <= 100) {
                    return origialPrice * 0.9; originalPrice
                } else {
                    return originalPrice - 20;
                }
            }
        }

        /* 存在问题：

        第一，它违反了单一职责原则（每个类或者函数都应该有一个单一的功能，并且该功能应该由这个类或者函数完全封装起来）。函数 getPrice 做了太多的事情，如果一个条件出现 bug ，整个函数就会崩溃（一处有问题，所有功能不能实现）

        第二，违反了开闭原则（对扩展开放，对修改关闭）。

        比如：新增一个活动 “疯狂星期四”crazy-thursday，规则为：

        价格低于或等于 100 元的产品以 20% 的折扣出售。
        价格高于 100 元但低于 200 元的产品将减少 20 元。
        价格高于或等于 200 元的产品将减少 20 元。
        
            if (status === "crazy-thursday") {
                if (origialPrice >= 100 && originalPrice < 200) {
                    return origialPrice - 20;
                } else if (originalPrice >= 200) {
                    return originalPrice - 50;
                } else {
                    return originalPrice * 0.8;
                }
            }
        */
        function defaultPrice(origialPrice) {
            return origialPrice;
        }

        function preSalePrice(origialPrice) {
            return origialPrice * 0.8;
        }

        function promotionPrice(origialPrice) {
            if (origialPrice <= 100) {
                return origialPrice * 0.9;
            } else {
                return originalPrice - 20;
            }
        }

        function crazyhursdayPrice(origialPrice) {
            if (origialPrice >= 100 && originalPrice < 200) {
                return origialPrice - 20;
            } else if (originalPrice >= 200) {
                return originalPrice - 50;
            } else {
                return originalPrice * 0.8;
            }
        }

        const priceStrategies = {
            "pre-sale": preSalePrice,
            "promotion": promotionPrice,
            "black-friday": crazyhursdayPrice,
            "default": defaultPrice,
        }

        function getPrice(originalPrice, status) {
            return priceStrategies[status](originalPrice);
        }
        // 测试
        const price = getPrice(200, 'pre-sale')
        console.log(price);
    </script>
</body>

</html>